home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / SYS / s / GHBackup.mrbk < prev    next >
Text File  |  1996-09-26  |  19KB  |  574 lines

  1. /*********************************************************************
  2. GHBackup.rexx Version 1.1 - Glenn Holliday's Automated Backup
  3.  
  4. AREXX program to run MRBackup for incremental backups.
  5.  
  6. Calling template:
  7.  
  8.     rx GHBackup [homePath [backupPath [lastFullBackupDate]]]
  9.  
  10. Description:
  11.  
  12.     This program can easily be adapted to your own set of backup
  13. rules.  You _do_ want to examine the code and tweak it, so it
  14. runs on the schedule you want to use for your personal backup
  15. policy.  Note in particular that most people will want to replace
  16. my own scheme for daily backups.  You'll likely either ignore dailies
  17. (you wouldn't do that, would you? :-) or set the parameters to format
  18. a new disk just like I have it doing for a weekly backup.
  19.  
  20. (Note: I've tagged some areas that are candidates for customization
  21.        with *** CUSTOMIZE *** - MRR.)
  22.  
  23. This software is completely public domain.
  24.  
  25. Author:
  26. -- 
  27. Glenn       | ...!uunet!anagld!dahlgren!glenn      (UUCP)
  28. Holliday    | glenn@dahlgren.sed.csc.com           (fully domained)
  29. Version 1:   October 1 1994
  30. Version 1.1: March  25 1995  Added check if a weekly backup is in
  31.                              same month as a full backup
  32.  
  33.     Since it's small, the complete software engineering document
  34. set follows.  I thought this might be interesting, it's the easiest
  35. way to explain what backup policies are and how I approached them,
  36. and it may answer questions of the form "why in the world is _that_
  37. in the code?"  Feel free to strip out this part if you wish:
  38.  
  39.     Problem analysis:
  40.  
  41.     Implement a set of rules to do incremental backups.
  42. Recognize daily, weekly, and monthly backups as different cases.
  43. Automatically run MRBackup and set up its parameters for each case.
  44.  
  45.     Backup rules:
  46.  
  47.     Keep a full backup set, a monthly backup set, a weekly
  48. backup set, and six daily backup sets (one for each day between
  49. weekly backups).  Backup every day.
  50.  
  51.     Assume that full backups (the entire disk) are done by hand
  52. when needed.  On the first day of a month, backup all files changed
  53. since the date of the most recent full backup.  On the first day of
  54. a week (Sunday), backup all files changed since the date of the most
  55. recent monthly backup.  On any other day, backup all files whose
  56. archive bits are clear (these are all files changed since the last
  57. backup).  On every backup, set the archive bits of all files backed
  58. up.
  59.  
  60.     Monthly and weekly backups are done to a set of diskettes.
  61. Daily backups (assuming a small amount of change each day) are done to
  62. subdirectories of a single diskette, named for each day.
  63.  
  64.     This program assumes that you keep a record of the date
  65. on which the most recent full backup was done.  It does not provide
  66. for making a full backup, or for storing that date.  Some interesting
  67. extensions could help out with that chore.  I do full backups whenever
  68. my set of monthly backup floppies overflows a box full, store the date
  69. in a file in s:, and have my "backupifold" script supply that date
  70. when it calls GHBackup.rexx.
  71.  
  72.     Design to automate the backup rules:
  73.  
  74. Run mrbackup.rexx daily.  In this program,
  75. Get the current date, day of week,
  76.         date of last monthly backup, and
  77.         date of last full backup.
  78. Classify current date as new month, new week, or ordinary day.
  79. (This partitions the set of all dates into equivalence
  80.  classes, where each equivalence class is identified by
  81.  one of the values of a data type with three possible values.)
  82. If the current date is:
  83.    new month,
  84.    new week,
  85.    ordinary day
  86. Run MRBackup with the selected parameters.
  87.  
  88.     Implementation:
  89.  
  90.     GHBackup.rexx is run daily by some other mechanism.  If you
  91. leave your system on all the time, you probably want to put an entry
  92. in your crontab to run it at the same time each day.  I turn my
  93. system off overnight, so I have cron run a program called "backupifold"
  94. several times a day.  It checks a timestamp of the last backup, and
  95. runs GHBackup.rexx if the timestamp is more than a day old.  I did not
  96. include this program because it uses some shenaigans I don't like to
  97. recogize elapsed time.  If I ever get around to writing the more
  98. elegant solution I have in mind, I'll give it away.
  99.  
  100.     Input arguments:
  101.  
  102.     If any of these are absent, GHBackup.rexx uses defaults.  The
  103. defaults are declared as ARexx variables at the beginning of the
  104. code.
  105.  
  106.      arg                 description                           default
  107.  
  108.      homePath            String, name of disk or other         DH1:
  109.                          filepath to the disk area to be
  110.                          backed up
  111.  
  112.      backupPath          String, filepath to the backup        DF0:
  113.                          medium or directory
  114.  
  115.      lastFullBackupDate  String, date in AmigaDOS format       Jan 1 1978
  116.                          on which the last full backup
  117.                          was done.
  118.  
  119.     This program follows the design outline, using several
  120. functions for modularity.  The outline of the code is as follows:
  121.  
  122. date = date()
  123. classifydate(date) 
  124. select
  125.    newmonth
  126.       setNewMonth()
  127.    newweek
  128.       setNewWeek()
  129.    daily
  130.       setNewDay()
  131. end of program
  132.  
  133. classifydate(date)
  134.    parse date to get day, month, year, day of week
  135.    if day is 1, classify as newmonth
  136.    else if day of week is Sunday, classify as newweek
  137.    else classify as daily
  138.    return classification
  139. setNewMonth():
  140.    (Back up everything since last full backup)
  141.    build "files since" date of last full backup,
  142.    select df0:, AmigaDos, quick format, ignore archive bits,
  143.    and no compression
  144. setNewWeek():
  145.    (Back up everything since last monthly backup.
  146.     Assume date of last monthly backup is the first of the month)
  147.    build "files since" first day of current month,
  148.    select df0:, AmigaDos, quick format, ignore archive bits,
  149.    and no compression
  150. setNewDay():
  151.    (Backup up everything since most recent backup.
  152.     Assume that's everything since archive bits were last set,
  153.     = everything with archive bits clear)
  154.    build backup path, AmigaDos, no format, test archive bits,
  155.    and 16 bit compression
  156. *********************************************************************/
  157.  
  158. /********************
  159. body of ARexx program
  160. ********************/
  161.  
  162. /*******************************************
  163. During debugging, want to see all the errors
  164. *******************************************/
  165. /* TRACE INTERMEDIATE */
  166.  
  167. signal on ERROR
  168. signal on BREAK_C
  169. options results
  170.  
  171. /*** CUSTOMIZE ***/
  172. defaultHomePath = "DH1:"
  173. defaultBackupPath = "DF0:"
  174. defaultLastFullBackup="01-Jan-78 00:00:00"
  175.  
  176. ARG homepath  backuppath lastFullBackup
  177.  
  178. if homepath = '' then
  179.    homepath = defaultHomePath
  180.  
  181. if backuppath = '' then
  182.    backuppath = defaultBackupPath
  183.  
  184. if lastFullBackup = '' then
  185.    lastFullBackup = defaultLastFullBackup
  186.  
  187. /****************************************************************
  188. Arexx parsing has the nasty habit of leaving the leading space on
  189. the last of a string of arguments that it parses from a command
  190. line.  There are code-intensive ways of checking and cleaning up
  191. all the arguments.  Since I know it'll only be a problem on the
  192. last one, here's a cheap way of cleaning it up.
  193. ****************************************************************/
  194.  
  195. lastFullBackup = strip(lastFullBackup)
  196.  
  197. /***************************************
  198. Be sure MRBackup is running.  Assume
  199. only one copy needed, always address the
  200. first MRBackup Rexx port.
  201. startMacro(port, program) is a standard
  202. Rexx macro that, if its first argument
  203. is not already there, runs its second
  204. argument and waits for its first
  205. argument to appear.
  206. ***************************************/
  207. toReturn = startServer('MRBackup_#1', 'mrbackup:mrbackup')
  208. address 'MRBackup_#1'
  209. takecontrol
  210. poptofront
  211.  
  212. /***************************************
  213. Get date, including weekday.
  214. ***************************************/
  215. date      = date('normal')
  216. weekday   = date('weekday')
  217.  
  218. /**********************************************
  219. returns dateclass = newmonth, newweek, or daily
  220. **********************************************/
  221. dateclass = classifydate(date, weekday)
  222.  
  223. /***************************************
  224. send ARexx commands to set MRBackup
  225. parameters for the type of date
  226. ***************************************/
  227. select
  228.    when dateclass = 'newmonth' then
  229.       toReturn = setNewMonth(homepath, backuppath, lastFullBackup)
  230.    when dateclass = 'newweek' then
  231.       toReturn = setNewWeek(homepath, backuppath, date, lastFullBackup)
  232.    when dateclass = 'daily' then
  233.       toReturn = setNewDaily(homepath, backuppath, weekday)
  234.    otherwise
  235.       do
  236.          Say 'unrecognized date type ' || dateclass
  237.          toReturn = 'FAIL'
  238.          error /* Use error: function to exit */
  239.       end
  240. end
  241.  
  242. /***************
  243. Start the backup
  244. ***************/
  245.  
  246. if toReturn = 'OK' then
  247.    do
  248.       backup
  249.       if rc ~= 0 then
  250.          do
  251.             say "Backup failed.  Error code: " || rc
  252.             error /* Exit through error handler */
  253.          end
  254.       quit /* command to MRBackup to quit */
  255.    end
  256. else
  257.    error
  258. exit 0 /* end of program, success return code */
  259.  
  260. /*********************************************************************
  261. classifydate(date, weekday)
  262.  
  263. Function to decide if a date is the first of month or week
  264. *********************************************************************/
  265.  
  266. classifydate:
  267.  
  268. date    = arg(1)
  269. weekday = arg(2)
  270. parse var date day month year garbageintail
  271. select
  272.    when day = 1 then
  273.       datetype = 'newmonth'
  274.    when weekday = 'Sunday' then
  275.       datetype = 'newweek'
  276.    otherwise
  277.       datetype = 'daily'
  278. end
  279.  
  280. return datetype
  281.  
  282. /*********************************************************************
  283. setNewMonth(homepath, backuppath, lastFullBackup)
  284.  
  285.      Inputs:
  286.          homepath            String, filepath to be backed up
  287.          backuppath          String, filepath to be backed up
  288.          lastFullBackup      String, date in AmigaDOS format of
  289.                              last full backup
  290.  
  291.     Function to set MRBackup's parameter for monthly backup.
  292. Back up everything since last full backup.  Build "files since" date
  293. of last full backup, select df0:, quick format, ignore archive bits,
  294. and no compression.
  295. *********************************************************************/
  296. setNewMonth:
  297.  
  298. homepath    = arg(1)
  299. backuppath  = arg(2)
  300. lastBackup  = arg(3)
  301.  
  302. /**********************************************************
  303. The date to backup from is midnight of the date of the last
  304. full backup.
  305. **********************************************************/
  306.  
  307. parse var lastBackup weekday datestring timestring
  308.  
  309. /*** CUSTOMIZE ***/
  310. testdate    = datestring || " 00:00:00"
  311. compression = 'None'
  312. formatting  = 'Quick'
  313. testbits    = 'No'
  314. comment     = "Monthly backup: All files since date of last full backup"
  315. toReturn = setParameters(homepath, backuppath, comment, compression, ,
  316.            formatting, testdate, testbits)
  317.  
  318. return toReturn
  319.  
  320. /*********************************************************************
  321. setNewWeek(homepath, backuppath, date, lastFullBackup)
  322.  
  323.      Inputs:
  324.          homepath   String, filepath to be backed up
  325.          backuppath String, filepath to be backed up
  326.          date       String, current date in ARexx form
  327.                     (day month year
  328.                      as opposed to AmigaDOS form day-month-year)
  329.          lastFullBackup String, current date in AmigaDos form
  330.                     (day-month-year)
  331.  
  332.     Function to set MRBackup's parameter for weekly backup.
  333. Back up everything since last monthly backup, = first day of the
  334. month in the input date.  If the last full backup happened during
  335. this month, use that date instead of the first of the month.
  336. Build "files since" date of the first of the month/last full backup,
  337. select df0:, quick format, ignore archive bits, and no compression.
  338.  
  339. March 18 1995:  Added check for last full backup since first of month
  340. *********************************************************************/
  341.  
  342. setNewWeek:
  343.  
  344. homepath   = arg(1)
  345. backuppath = arg(2)
  346. date       = arg(3)
  347. lastfullbackup = arg(4)
  348.  
  349. /*************************************************
  350. Translate lastfullbackup from day-month-year to day month year
  351. Get the month, check if lastfullbackup was in same month.
  352. Set new date to first day or month or lastfullbackup.
  353. Translate 19yy to yy, use midnight on the first.
  354. *************************************************/
  355. lastfullbackup = translate(lastfullbackup, " ", "-")
  356. parse var date oldday month year rest
  357. parse var lastfullbackup dayname fullday fullmonth fullyear rest
  358.  
  359. /*****************************************
  360. Get months in all uppercase for comparison
  361. *****************************************/
  362. month     = translate(month)
  363. fullmonth = translate(fullmonth)
  364. yearpart     = right(year, 2)
  365. fullyearpart = right(fullyear, 2)
  366. if month = fullmonth & yearpart = fullyearpart then
  367.    do
  368.       testdate    = fullday || '-' || fullmonth || '-' || fullyearpart || " 00:00:00"
  369.       /* testdate = lastfullbackup */
  370.       comment  = "Weekly backup: All files since date of last full backup"
  371.    end
  372. else
  373.    do
  374.       testdate    = '01-' || month || '-' || yearpart || " 00:00:00"
  375.       comment     = "Weekly backup: All files since first of this month"
  376.    end
  377.  
  378. /*** CUSTOMIZE ***/
  379. compression = 'None'
  380. formatting  = 'Quick'
  381. testbits    = 'No'
  382. toReturn = setParameters(homepath, backuppath, comment, compression, ,
  383.                          formatting, testdate, testbits)
  384.  
  385. return toReturn
  386.  
  387. /*********************************************************************
  388. setNewDaily(homepath, backuppath, weekday)
  389.  
  390.      Inputs:
  391.          homepath   String, filepath to be backed up
  392.          backuppath String, filepath to be backed up
  393.          weekday    String, current day of the week
  394.  
  395.     Function to set MRBackup's parameters for daily backup.
  396. Back up everything that has archive bits clear, build a backup
  397. filename from the current weekday, no format, and 16-bit compression.
  398. *********************************************************************/
  399. setNewDaily:
  400.  
  401. homepath   = arg(1)
  402. backupdev  = arg(2)
  403. weekday    = arg(3)
  404.  
  405. /*** CUSTOMIZE ***/
  406. backuppath = backupdev || weekday || "/"
  407. testdate    = 'nil'
  408. compression = '16-Bit'
  409. formatting  = 'None'
  410. testbits    = 'Yes'
  411. comment     = "Daily backup: All files with archive bit clear"
  412. toReturn = setParameters(homepath, backuppath, comment, compression, ,
  413.    formatting, testdate, testbits)
  414.  
  415. return toReturn
  416.  
  417. /*********************************************************************
  418. setParameters(homepath, backuppath, comment, compression, formatting,
  419.               testdate, testbits)
  420.  
  421.      Inputs:
  422.         homepath   String, filepath to disk area to back up
  423.         backuppath String, filepath to disk to which the backup
  424.                    is to be saved
  425.         comment    String, to display in MRBackup's comment gadget.
  426.                    Informs user what type of backup is being done.
  427.         compression String, None or 16-Bit.
  428.         testdate   String, an AmigaDOS date or nil.  nil indicates
  429.                    the date is not tested.
  430.         testbits   String, YES or NO.  If archive bits are tested,
  431.                    testdate is not used.  If archive bits are not
  432.                    tested, testdate is used.
  433.  
  434.      Returns:
  435.         toReturn   String, OK or FAIL (conforms to the code returned
  436.                    by each MRBackup command).  Tells the caller if
  437.                    everything was set successfully.
  438.  
  439.      This function sends ARexx commands to MRBackup to set the
  440. parameters calculated by earlier functions.  It tests for successful
  441. completion of each ARexx message.
  442.  
  443.     Assume that standard parameters common to all types
  444. of backups (e.g. mode = AmigaDOS) are set in the usual
  445. MRBackup.init, which MRBackup loaded on startup.
  446. *********************************************************************/
  447.  
  448. setParameters:
  449. arg homepath, backuppath, comment, compression, formatting, testdate, ,
  450.     testbits
  451.  
  452. /*************************************************
  453. Check the backup disk is present before giving the
  454. setbackpath command.  If it's a device name,
  455. MRBackup checks it when it's time to begin writing
  456. to it.  If it contains a directory path,
  457. MRBackup requires that directory be available on
  458. a mounted device when the setbackpath command
  459. is issued.
  460. *************************************************/
  461. if right(backuppath, 1) ~= ':' then
  462.    do while ~exists(backuppath)
  463.       string = "'Please mount " || backuppath || " in any drive'"
  464.       'getchoice' '"'string'"' 'OK'
  465.    end
  466.  
  467. setfilemode "Replace"
  468.  
  469. /***************************
  470. This section sets all the
  471. MRBackup parameters.  The
  472. strategy is:
  473.  
  474.  set a parameter
  475.  as long as no error yet,
  476.     keep going to set more
  477.  
  478. Most of the ARexx commands
  479. put a return code, OK or
  480. FAIL, in the variable
  481. result.  Test result after
  482. each command, and keep going
  483. as long as it's OK.
  484.  
  485. Some of the commands put
  486. something else in result.
  487. For these, check the ARexx
  488. return variable rc.  Set
  489. result to indicate the same
  490. state that rc indicates.
  491. This keeps the current
  492. state consistent in result,
  493. and lets it be used
  494. consistently to test if
  495. the next parameter should
  496. be tested.
  497.  
  498. If any command returns
  499. a failure code, all of
  500. the remaining tests
  501. fall through, and no
  502. more commands are sent to
  503. MRBackup.
  504. ***************************/
  505.  
  506. if result ~= 'FAIL' then
  507.     setbackpath backuppath    /* returns result = OK or FAIL             */
  508. if result ~= 'FAIL' then
  509.    sethomepath homepath       /* returns result = current path, check rc */
  510. if rc ~= 0 then
  511.    do
  512.       result = 'FAIL'
  513.    end
  514. else
  515.    listing 'YES'                          /* returns result = OK or FAIL */
  516. if result ~= 'FAIL' then
  517.    setarcbits 'yes'    /* always set the bits after we finish backing up */
  518. if result ~= 'FAIL' then
  519.    'setinfogadget' '"'comment'"'          /* always returns result = OK  */
  520. if result = 'OK' then
  521.    'setcompression' '"'compression'"'     /* returns result = OK or FAIL */
  522. if result ~= 'FAIL' then
  523.    'setformatting' '"'formatting'"'    /* returns current mode, check rc */
  524. if rc ~= 0 then
  525.    do
  526.       result = 'FAIL'
  527.    end
  528. else
  529.    'testarcbits' '"'testbits'"' /* Set "test bits" to either Yes or No */
  530. if result ~= 'FAIL' then
  531.    do
  532.    /***********************************************
  533.    only test date if we aren't testing archive bits
  534.    ***********************************************/
  535.    if testbits = 'NO' then
  536.       do
  537.          'dateformat 0'
  538.          settestdate '"'testdate'"' /* returns current date, check rc */
  539.          if rc ~= 0 then result = 'FAIL'
  540.          else result = 'OK'
  541.       end
  542.    end
  543.  
  544. return result
  545.  
  546. /*********************************************************************
  547. error
  548.  
  549.      This function handles an error condition.  It exits with
  550. return code 6, which is 1 higher than a warning.  It sends a
  551. quit to MRBackup.
  552. *********************************************************************/
  553. error:
  554.  
  555. say "Exiting because of error"
  556. quit /* command to MRBackup to quit */
  557. exit 6
  558.  
  559. /*********************************************************************
  560. break_c
  561.  
  562.      This function exits the ARexx script on a user control-c
  563. interrupt.  It does not stop MRBackup.  It exits with return code
  564. 5, which is a warning.
  565. *********************************************************************/
  566. break_c:
  567.  
  568. say "*** Control-C recieved.  Stopped by user. ***"
  569. /* Note:  Do not command to MRBackup to quit.  Leave running, assume
  570. user needs to look at something.
  571. */
  572. exit 5
  573.  
  574.